/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.cmd.task;

import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.WorkflowContext;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.LogDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.engine.runtime.PageTaskSupport;
import cn.easyplatform.engine.runtime.RuntimeTask;
import cn.easyplatform.engine.runtime.RuntimeTaskFactory;
import cn.easyplatform.engine.runtime.datalist.DataListUtils;
import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.beans.task.DecisionBean;
import cn.easyplatform.entities.beans.task.TaskBean;
import cn.easyplatform.entities.beans.task.TransitionBean;
import cn.easyplatform.entities.helper.EventLogic;
import cn.easyplatform.i18n.I18N;
import cn.easyplatform.interceptor.AbstractCommand;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.AbstractResponseMessage;
import cn.easyplatform.messages.request.BeginRequestMessage;
import cn.easyplatform.messages.request.ListBatchRequestMessage;
import cn.easyplatform.messages.response.SimpleResponseMessage;
import cn.easyplatform.messages.response.TaskNextErrorResponseMessage;
import cn.easyplatform.messages.vos.TaskVo;
import cn.easyplatform.messages.vos.datalist.ListBatchVo;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.util.EntityUtils;
import cn.easyplatform.util.MessageUtils;
import cn.easyplatform.util.RuntimeUtils;

import java.util.Collections;
import java.util.Map;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class BatchCmd extends AbstractCommand<ListBatchRequestMessage> {

    /**
     * @param req
     */
    public BatchCmd(ListBatchRequestMessage req) {
        super(req);
    }

    @Override
    public IResponseMessage<?> execute(CommandContext cc) {
        WorkflowContext ctx = cc.getWorkflowContext();
        ListBatchVo bv = req.getBody();
        ListContext lc = ctx.getList(bv.getId());
        Object[] keys = bv.getKeys().remove(0);
        if (lc.isCustom()) {
            FieldDo[] data = DataListUtils.getRow(cc, lc, keys);
            Record record = new Record();
            for (int i = 0; i < data.length; i++)
                record.set(data[i]);
            ctx.setData(record);
        } else {
            lc.lock(cc, keys);
            ctx.setData(DataListUtils.getRecord(cc, lc, keys));
        }
        ctx.setPendingList(bv);
        ctx.setParameter("814", "R");
        ctx.setParameter("833", lc.getBean().getTable());
        ctx.setParameter("854", true);
        PageTaskSupport support = (PageTaskSupport) RuntimeTaskFactory
                .createRuntime(EntityType.PAGE.getName());
        Map<String, Object> data = Collections.emptyMap();
        IResponseMessage<?> resp = support.doNext(cc, data);
        if (resp != null) {
            // 如果是不显示的功能，需要返回到之前有显示的页面
            if (!ctx.getParameterAsBoolean("816")) {
                if (ctx.prev(cc)) {
                    return new TaskNextErrorResponseMessage(
                            support.doPrev(cc), resp);
                } else {
                    cc.removeWorkflowContext();
                    return new TaskNextErrorResponseMessage(
                            new SimpleResponseMessage(), resp);
                }
            }
            return resp;
        }
        DecisionBean db = ctx.getAs(DecisionBean.class, "817");
        if (db != null)
            return doNext(cc, ctx, db, bv.getCode());
        else
            return doCommit(cc, ctx);
    }

    private IResponseMessage<?> doCommit(CommandContext cc, WorkflowContext ctx) {
        ctx.commit(cc);
        if (cc.getUser().getLogLevel() >= LogDo.LEVEL_TASK)
            RuntimeUtils.log(cc, LogDo.TYPE_TASK, "commit",
                    ctx.getParameterAsString("801"));
        char rt = ctx.getParameterAsChar("804");
        if (rt == '1') {
            // 重新执行功能
            TaskVo tv = new TaskVo(ctx.getParameterAsString("801"));
            cc.removeWorkflowContext();
            IResponseMessage<?> resp = new BeginCmd(new BeginRequestMessage(tv))
                    .execute(cc);
            // 增加标识，以便客户端辩别及后继的处理，参考TaskSupport.next
            ((AbstractResponseMessage) resp).setRedo(true);
            return resp;
        } else if (rt == '2') {
            // 回到第一个功能
            ctx.reset(cc);
            ctx.setParameter("759", "Prev");
            PageTaskSupport support = (PageTaskSupport) RuntimeTaskFactory
                    .createRuntime(EntityType.PAGE.getName());
            return support.doPrev(cc);
        } else {
            cc.removeWorkflowContext();
            return new SimpleResponseMessage();
        }
    }

    private IResponseMessage<?> doNext(CommandContext cc, WorkflowContext ctx,
                                       DecisionBean db, String code) {
        TransitionBean transition = null;
        if (Strings.isBlank(db.getExpr())) {
            if (db.getTransitions() == null || db.getTransitions().isEmpty())
                return doCommit(cc, ctx);
            else
                transition = db.getTransitions().get(0);
        } else {
            String name = (String) RuntimeUtils.evalExpr(cc, db.getExpr(),
                    ctx.getRecord());
            if (Strings.isBlank(name))
                return doCommit(cc, ctx);
            for (TransitionBean tb : db.getTransitions()) {
                if (tb.getName().equals(name)) {
                    transition = tb;
                    break;
                }
            }
            if (transition == null)
                return doCommit(cc, ctx);
        }
        String taskId = transition.getTo().trim();
        if (taskId.charAt(0) == '$')
            taskId = (String) ctx.getRecord().getValue(taskId.substring(1));
        TaskBean task = cc.getEntity(taskId);
        if (task == null)
            return MessageUtils.entityNotFound(EntityType.TASK.getName(),
                    taskId);
        task = EntityUtils.getInheritTask(cc, ctx.getRecord(), task);
        String refId = task.getRefId();
        if (!Strings.isBlank(refId) && refId.startsWith("$")
                && cc.getWorkflowContext() != null)
            refId = (String) cc.getWorkflowContext().getRecord()
                    .getValue(refId.substring(1));
        if (refId == null)
            return MessageUtils.entityNotFound(EntityType.PAGE.getName(),
                    task.getRefId());
        BaseEntity base = cc.getEntity(refId);
        if (base == null)
            return MessageUtils.entityNotFound(EntityType.PAGE.getName(),
                    task.getRefId());
        RuntimeTask runtime = RuntimeTaskFactory.createRuntime(base.getType());
        EventLogic el = null;
        if (!Strings.isBlank(transition.getLogicId())) {
            el = new EventLogic();
            el.setId(transition.getLogicId());
        } else if (!Strings.isBlank(transition.getMappings())) {
            el = new EventLogic();
            el.setContent(transition.getMappings());
        }
        task = task.clone();
        if (el != null) {
            task.setOnInit(el);
            if (!Strings.isBlank(code))
                task.setProcessCode(code);
        } else if (!Strings.isBlank(code)) {
            task.setProcessCode(code);
        }
        task.setName(RuntimeUtils.getLabel(cc, task.getName()));
        String layer = transition.getFrom();
        if (!Strings.isBlank(layer)) {
            if (layer.startsWith("$")) {
                Object obj = ctx.getRecord().getValue(layer.substring(1));
                if (obj != null)
                    layer = obj.toString();
            }
            if (!ctx.next(Nums.toInt(layer, -1), task))
                return new SimpleResponseMessage("E017", I18N.getLabel(
                        "context.from.not.found", layer));
        } else
            ctx.next(-1, task);
        IResponseMessage<?> resp = runtime.doTask(cc, base);
        if (resp.isSuccess())
            ctx.store();
        else {
            char c = resp.getCode().toLowerCase().charAt(0);
            if (c != 'c' && c != 'w')
                ctx.prev(cc);
        }
        return resp;
    }

    @Override
    public String getName() {
        return "task.Batch";
    }
}
